﻿using Styx;
using Styx.Common;
using Styx.CommonBot;
using Styx.CommonBot.Frames;
using Styx.CommonBot.Routines;
using Styx.Pathing;
using Styx.TreeSharp;
using Styx.WoWInternals;
using Styx.WoWInternals.WoWObjects;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Media;
using Action = Styx.TreeSharp.Action;

namespace FrostDK
{
    public class Main : CombatRoutine
    {

        public override string Name { get { return "Frost DK Routine by Pasterke"; } }
        public override WoWClass Class { get { return WoWClass.DeathKnight; } }
        public LocalPlayer Me { get { return StyxWoW.Me; } }


        public override Composite CombatBehavior { get { return CreateCombat(); } }
        public override Composite PullBehavior { get { return CreatePull(); } }
        public override Composite PullBuffBehavior { get { return CreatePullBuffs(); } }
        public override Composite PreCombatBuffBehavior { get { return CreatePreCombatBuffs(); } }
        public override Composite CombatBuffBehavior { get { return CreateCombatBuffs(); } }
        public override Composite RestBehavior { get { return CreateRestBehavior(); } }



        public int addCount { get { return UnfriendlyUnits.Count(); } }
        public string shapeForm = string.Empty;
        public string usedBot { get { return BotManager.Current.Name.ToUpper(); } }

        private static bool MeIsInGame
        {
            get { return StyxWoW.IsInGame; }
        }

        #region show form
        public override bool WantButton { get { return true; } }

        public override void OnButtonPress()
        {
            Form1 ConfigForm = new Form1();
            ConfigForm.ShowDialog();
        }
        #endregion

        #region initialize
        public override void Initialize()
        {
            if (CRSettingsFrost.myPrefs.AutoUpdate)
            {
                Updater.CheckForUpdate(UpdateSettingsFrost.myPrefs.Revision);
            }
            Lua.Events.AttachEvent("MODIFIER_STATE_CHANGED", HandleModifierStateChanged);
            EventHandlers.AttachCombatLogEvent();

        }
        #endregion

        #region pulse
        public override void Pulse()
        {
            try
            {
                if (Me.IsDead
                    && usedBot.Contains("QUEST")
                    || usedBot.Contains("GRIND")
                    || usedBot.Contains("GATHER"))
                {
                    Lua.DoString(string.Format("RunMacroText(\"{0}\")", "/script RepopMe()"));
                }
                if (!Me.Combat && (usedBot.Contains("QUEST") || usedBot.Contains("GRIND")) && Lootables.Count() >= 1)
                {
                    GetLoot();
                }
                if (usedBot.Contains("ANGLER")
                    && (!buffExists(PATH_OF_FROST, Me)
                    || (buffExists(PATH_OF_FROST, Me) && buffTimeLeft(PATH_OF_FROST, Me) <= 50000))

                    && !Me.Combat
                    && SpellManager.CanCast(PATH_OF_FROST))
                {
                    SpellManager.Cast(PATH_OF_FROST, Me);
                    Logging.Write(Colors.LightBlue, "Path of Frost with AutoAngler");
                }
                return;
            }
            catch { }
        }
        #endregion

        #region shutdown
        public override void ShutDown()
        {
            Lua.Events.DetachEvent("MODIFIER_STATE_CHANGED", HandleModifierStateChanged);
            EventHandlers.DetachCombatLogEvent();
        }
        #endregion

        public Composite CreateRestBehavior()
        {
            return new PrioritySelector(
                new Decorator(ret => Paused, PauseCR()),
                new Decorator(ret => !Me.Combat
                    && CanBuffEat
                    && Me.HealthPercent <= CRSettingsFrost.myPrefs.FoodPercent
                    && !Me.GroupInfo.IsInRaid
                    && !Me.IsInInstance,
                    new Action(ret =>
                    {
                        Styx.CommonBot.Rest.Feed();

                    }))
                );
        }
        public Composite CreatePreCombatBuffs()
        {
            return new PrioritySelector(
                new Decorator(ret => Paused, PauseCR()),
                Cast("Frost Presence", ret => !Me.HasAura("Frost Presence"))
                );
        }
        public Composite CreatePull()
        {
            return new PrioritySelector(
                new Decorator(ret => Paused, PauseCR()),
                new Decorator(ret => gotTarget && !Me.IsSafelyFacing(Me.CurrentTarget), FaceMyTarget()),
                new Decorator(ret => gotTarget && Me.CurrentTarget.Distance > myRange, CreateMovementBehavior()),
                new Decorator(ret => gotTarget && Me.CurrentTarget.Distance <= myRange, CreateStopMovement()),
                Cast("Outbreak", ret => gotTarget && !spellOnCooldown(OUTBREAK)),
                Cast("Death Grip", ret => gotTarget && !spellOnCooldown(DEATH_GRIP)),
                Cast("Icy Touch", ret => gotTarget),
                Cast("Death Coil", ret => gotTarget)
                );
        }
        public Composite CreatePullBuffs()
        {
            return new PrioritySelector(
                new Decorator(ret => Paused, PauseCR()),
                Cast("Horn of Winter", ret => !spellOnCooldown(HORN_OF_WINTER))
                );
        }
        
        public Composite CreateCombatBuffs()
        {
            return new PrioritySelector(
                new Decorator(ret => Paused, PauseCR()),
                Cast("Horn of Winter", ret => CanBuffEat && !buffExists(HORN_OF_WINTER, Me) && !spellOnCooldown(HORN_OF_WINTER)),
                CastOnMe("Icebound Fortitude", ret => CanBuffEat && gotTarget && !spellOnCooldown(ICEBOUND_FORTITUDE) && Me.HealthPercent <= CRSettingsFrost.myPrefs.IceboundFortitudePercent),
                Cast("Anti-Magic Shell", ret => CanBuffEat && gotTarget && Me.CurrentTarget.IsCasting && !spellOnCooldown(ANTI_MAGIC_SHELL)),
                Cast("Rune Tap", ret => CanBuffEat && gotTarget && !spellOnCooldown(RUNE_TAP) && Me.HealthPercent <= CRSettingsFrost.myPrefs.RuneTapPercent),
                Cast("Lichborne", ret => IsCrowdControlledPlayer(Me) && !spellOnCooldown("Lichborne"))
                );
        }
        public Composite CreateCombat()
        {
            return new PrioritySelector(
                new Decorator(ret => Paused, PauseCR()),
                new Decorator(ret => Me.CurrentTarget != null && Me.CurrentTarget.IsFriendly && !Me.CurrentTarget.IsPlayer, ClearMyTarget()),
                new Decorator(ret => Me.CurrentTarget != null && Me.CurrentTarget.IsDead, ClearMyTarget()),
                new Decorator(ret => Me.CurrentTarget == null, new Action(ret => { FindTarget(); return RunStatus.Failure; })),
                new Decorator(ret => gotTarget && AllowFacing && !Me.IsSafelyFacing(Me.CurrentTarget), FaceMyTarget()),
                new Decorator(ret => gotTarget && AllowMovement && Me.CurrentTarget.Distance > myRange, CreateMovementBehavior()),
                new Decorator(ret => gotTarget && AllowMovement && Me.CurrentTarget.Distance <= myRange && Me.IsMoving, CreateStopMovement()),
                new Decorator(ret => gotTarget && !Me.IsAutoAttacking, AutoAttack()),
                new Decorator(ret => CRSettingsFrost.myPrefs.AutoResTank
                    && (Me.CurrentMap.IsRaid || Me.CurrentMap.IsDungeon || Me.CurrentMap.IsScenario || Me.CurrentMap.IsInstance)
                    && AnyTankNearby
                    && !spellOnCooldown("Raise Ally"), ResTank()),
                new Decorator(ret => CRSettingsFrost.myPrefs.AutoResHealer
                    && (Me.CurrentMap.IsRaid || Me.CurrentMap.IsDungeon || Me.CurrentMap.IsScenario || Me.CurrentMap.IsInstance)
                    && AnyHealerNearby
                    && !spellOnCooldown("Raise Ally"), ResHealer()),

                //Frost Rotation
                new Decorator(ret => Me.Specialization == WoWSpec.DeathKnightFrost,
                    new PrioritySelector(
                        Cast("Death Coil", ret => gotTarget && !Me.CurrentTarget.IsWithinMeleeRange && Me.IsSafelyBehind(Me.CurrentTarget)),
                        Cast("Chains of Ice", ret => gotTarget && !Me.CurrentTarget.IsWithinMeleeRange && Me.IsSafelyBehind(Me.CurrentTarget)),
                        Healthstone(),
                        Cast("Death Pact", ret => gotTarget && Me.HealthPercent <= CRSettingsFrost.myPrefs.DeathPactPercent),
                        InterruptTarget(),
                        StunningTarget(),
                        Cast("Plague Leech", ret => gotTarget 
                            && !spellOnCooldown("Plague Leech") 
                            && Me.DeathRuneCount < 1 
                            && debuffExists("Blood Plague", Me.CurrentTarget) 
                            && debuffExists("Frost Fever", Me.CurrentTarget)),
                        Cast("Empower Rune Weapon", ret => gotTarget && !spellOnCooldown("Empower Rune Weapon")
                            && Me.DeathRuneCount < 1 && Me.BloodRuneCount < 1 && Me.UnholyRuneCount < 1 && Me.FrostRuneCount < 1
                            && IsWoWBoss(Me.CurrentTarget)),
                        Cast("Outbreak", ret => gotTarget 
                            && !debuffExists("Frost Fever", Me.CurrentTarget) 
                            && !debuffExists("Blood Plague", Me.CurrentTarget)
                            && !spellOnCooldown(OUTBREAK)),
                        Cast("Icy Touch", ret => gotTarget && !debuffExists("Frost Fever", Me.CurrentTarget)),
                        Cast("Plague Strike", ret => gotTarget
                            && (UnfriendlyUnits.Count() >= CRSettingsFrost.myPrefs.DeathAndDecayAdds
                            && spellOnCooldown(DEATH_AND_DECAY))
                            || !debuffExists("Blood Plague", Me.CurrentTarget)),
                        Cast(PILLAR_OF_FROST, ret => gotTarget && !spellOnCooldown(PILLAR_OF_FROST)),
                        Cast("Raise Dead", ret => gotTarget && !spellOnCooldown("Raise Dead")),
                        new Decorator(ret => buffExists(PILLAR_OF_FROST, Me) && CRSettingsFrost.myPrefs.AutoTrinket1 && CRSettingsFrost.myPrefs.trinket1dpsboost, Trinket1()),
                        new Decorator(ret => buffExists(PILLAR_OF_FROST, Me) && CRSettingsFrost.myPrefs.AutoTrinket2 && CRSettingsFrost.myPrefs.trinket2dpsboost, Trinket2()),
                        new Decorator(ret => buffExists(PILLAR_OF_FROST, Me) && CRSettingsFrost.myPrefs.AutoTrinket1 && !CRSettingsFrost.myPrefs.trinket1dpsboost, Trinket1()),
                        new Decorator(ret => buffExists(PILLAR_OF_FROST, Me) && CRSettingsFrost.myPrefs.AutoTrinket2 && !CRSettingsFrost.myPrefs.trinket2dpsboost, Trinket2()),
                        Cast("Unholy Blight", ret => gotTarget && PestilenceAdds.Count() >= 2 && !spellOnCooldown("Unholy Blight")),
                        Cast("Remorseless Winter", ret => gotTarget && (UnfriendlyUnits.Count() >= CRSettingsFrost.myPrefs.RemorselessWinterAdds || Me.CurrentTarget.IsPlayer)),
                        DropCast("Death and Decay", ret => gotTarget && UnfriendlyUnits.Count() >= CRSettingsFrost.myPrefs.DeathAndDecayAdds && !spellOnCooldown(DEATH_AND_DECAY)),
                        Cast("Soul Reaper", ret => gotTarget && Me.CurrentTarget.HealthPercent < 35),
                        Cast(OBLITERATE, ret => gotTarget && Me.RunicPowerPercent <= 75 || buffExists(KILLING_MACHINE, Me)),
                        Cast("Blood Tap", ret => gotTarget
                            && (buffExists(BLOOD_CHARGE, Me) && buffStackCount(BLOOD_CHARGE, Me) > 5)
                            && Me.DeathRuneCount <= 1
                            && lastCast != BLOOD_TAP),
                        Cast(HOWLING_BLAST, ret => gotTarget && (buffExists(RIME, Me) || UnfriendlyUnits.Count() >= CRSettingsFrost.myPrefs.DeathAndDecayAdds)),
                        Cast(FROST_STRIKE, ret => gotTarget),
                        Cast("Pestilence", ret => gotTarget && PestilenceAdds.Count() >= 2 && !buffExists("Unholy Blight", Me))

                        )),



                //Blood Rotation
                new Decorator(ret => Me.Specialization == WoWSpec.DeathKnightBlood,
                    new PrioritySelector(

                        ))
                );
        }


        #region spells
        string FROST_STRIKE = "Frost Strike";
        string HOWLING_BLAST = "Howling Blast";
        string RIME = "Rime";
        string OBLITERATE = "Obliterate";
        string KILLING_MACHINE = "Killing Machine";
        string PILLAR_OF_FROST = "Pillar of Frost";
        int BLOOD_CHARGE = 114851;
        public int DEATH_GRIP = 49576;
        public int DARK_COMMAND = 56222;
        public int ICY_TOUCH = 45477;
        public int PLAGUE_STRIKE = 45462;
        public int HEART_STRIKE = 55050;
        public int DEATH_STRIKE = 49998;
        public int DEATH_COIL = 47541;
        public int RUNE_STRIKE = 56815;
        public int BLOOD_BOIL = 48721;
        public int DEATH_AND_DECAY = 43265;
        public int ANTI_MAGIC_SHELL = 48707;
        public int RUNE_TAP = 48982;
        public int ICEBOUND_FORTITUDE = 48792;
        public int ASPHYXIATE = 108194;
        public int CHAINS_OF_ICE = 45524;
        public int MIND_FREEZE = 47528;
        public int PESTILENCE = 50842;
        public int LIFEBLOOD = 55501;
        public int LICHBORNE = 49039;
        public int RAISE_DEAD = 46584;
        public int DEATH_PACT = 48743;
        public int HORN_OF_WINTER = 57330;
        public int PATH_OF_FROST = 3714;
        public int DANCING_RUNE_WEAPON = 49028;
        public int OUTBREAK = 77575;
        public int NECROTIC_STRIKE = 73975;
        public int SOUL_REAPER = 114866;
        public int DARK_SIMULACRUM = 77606;
        public int FROST_FEVER = 55095;
        public int BLOOD_PLAGUE = 55078;
        public int BONE_SHIELD = 49222;
        public int BLOOD_CHARGE_BUFF = 114851;
        public int BLOOD_TAP = 45529;
        public int REMORSELESS_WINTER = 108200;
        public int GOREFIEND_GRASPS = 108199;
        public int DEATH_SIPHON = 108196;
        #endregion

        #region clear dead target
        Composite ClearMyTarget()
        {
            return new Action(ret =>
            {
                Me.ClearTarget();
                return RunStatus.Failure;
            });
        }
        #endregion

        #region can buff and eat
        public bool CanBuffEat
        {
            get
            {
                return !Me.Mounted && !Me.IsFlying && !Me.OnTaxi && !Me.IsDead && !Me.IsGhost;
            }
        }
        #endregion

        #region gotTarget
        public bool gotTarget
        {
            get
            {
                return Me.CurrentTarget != null && CanAttackCurrentTarget;
            }
        }
        #endregion

        #region overlayed
        public bool IsOverlayed(int spellID)
        {
            return Lua.GetReturnVal<bool>("return IsSpellOverlayed(" + spellID + ")", 0);
        }
        #endregion overlayed

        #region spellcharges
        public static double GetSpellCharges(int spellID)
        {
            return Lua.GetReturnVal<int>("return GetSpellCharges(" + spellID + ")", 0);
        }
        #endregion

        #region spellcasting
        private delegate T Selection<out T>(object context);
        Composite Cast(string spell, Selection<bool> reqs = null)
        {
            return
                new Decorator(
                    ret => ((reqs != null && reqs(ret)) || (reqs == null)) && SpellManager.CanCast(spell),
                    new Action(ret =>
                    {
                        SpellManager.Cast(spell);
                        Logging.Write(spell);
                    }
                        ));
        }
        Composite CastOnMe(string spell, Selection<bool> reqs = null)
        {
            return
                new Decorator(
                    ret => ((reqs != null && reqs(ret)) || (reqs == null)) && SpellManager.CanCast(spell),
                    new Action(ret =>
                    {
                        SpellManager.Cast(spell, Me);
                        Logging.Write(spell);
                    }
                        ));
        }
        Composite DropCast(string spell, Selection<bool> reqs = null)
        {
            return
                new Decorator(
                    ret => ((reqs != null && reqs(ret)) || (reqs == null)) && SpellManager.CanCast(spell),
                    new Action(ret =>
                    {
                        SpellManager.Cast(spell);
                        SpellManager.ClickRemoteLocation(Me.CurrentTarget.Location);
                        Logging.Write(spell);
                    }
                        ));
        }
        public static TimeSpan GetSpellCooldown(string spell)
        {
            SpellFindResults results;
            if (SpellManager.FindSpell(spell, out results))
            {
                if (results.Override != null)
                    return results.Override.CooldownTimeLeft;
                return results.Original.CooldownTimeLeft;
            }


            return TimeSpan.MaxValue;
        }
        #endregion

        #region addcount
        IEnumerable<WoWUnit> UnfriendlyUnits
        {
            get
            {
                return ObjectManager.GetObjectsOfType<WoWUnit>(true, false).Where(u => u != null
                    && !u.IsFriendly
                    && u.CanSelect
                    && !u.IsDead
                    && !u.IsCritter
                    && !u.IsNonCombatPet
                    && !u.IsTotem
                    && u.DistanceSqr <= 8 * 8);
            }
        }
        IEnumerable<WoWUnit> Goregaspadds
        {
            get
            {
                return ObjectManager.GetObjectsOfType<WoWUnit>(true, false).Where(u => u != null
                    && !u.IsFriendly
                    && u.CanSelect
                    && !u.IsDead
                    && !u.IsCritter
                    && !u.IsNonCombatPet
                    && !u.IsTotem
                    && (u.Location.Distance(Me.Location) >= 10 && u.Location.Distance(Me.Location) <= 20));
            }
        }
        IEnumerable<WoWUnit> PestilenceAdds
        {
            get
            {
                return ObjectManager.GetObjectsOfType<WoWUnit>(true, false).Where(u => u != null
                    && !u.IsFriendly
                    && u.CanSelect
                    && !debuffExists("Frost Fever", u) 
                    && !debuffExists("Blood Plague", u)
                    && !u.IsDead
                    && !u.IsCritter
                    && !u.IsNonCombatPet
                    && !u.IsTotem
                    && u.DistanceSqr <= 15 * 15);
            }
        }
        #endregion

        #region movement targeting facing
        [DllImport("user32.dll")]
        private static extern short GetAsyncKeyState(Keys vKey);

        public bool AllowFacing
        {
            get
            {
                if (CRSettingsFrost.myPrefs.DisableAutoFacing
                    && (Me.GroupInfo.IsInRaid || Me.IsInInstance || Me.GroupInfo.PartyMembers.Count() >= 3))
                {
                    return false;
                }
                if ((GetAsyncKeyState(Keys.LButton) != 0
                    && GetAsyncKeyState(Keys.RButton) != 0) ||
                    GetAsyncKeyState(Keys.W) != 0 ||
                    GetAsyncKeyState(Keys.S) != 0 ||
                    GetAsyncKeyState(Keys.D) != 0 ||
                    GetAsyncKeyState(Keys.A) != 0)
                {
                    return false;
                }
                return CRSettingsFrost.myPrefs.AutoFacing;

            }
        }
        public bool AllowTargeting
        {
            get
            {
                if (CRSettingsFrost.myPrefs.DisableAutoTargeting
                    && (Me.GroupInfo.IsInRaid || Me.IsInInstance || Me.GroupInfo.PartyMembers.Count() > 3))
                {
                    return false;
                }
                if ((GetAsyncKeyState(Keys.LButton) != 0
                    && GetAsyncKeyState(Keys.RButton) != 0) ||
                    GetAsyncKeyState(Keys.W) != 0 ||
                    GetAsyncKeyState(Keys.S) != 0 ||
                    GetAsyncKeyState(Keys.D) != 0 ||
                    GetAsyncKeyState(Keys.A) != 0)
                {
                    return false;
                }
                return CRSettingsFrost.myPrefs.AutoTargeting;
            }
        }
        public bool AllowMovement
        {
            get
            {
                if (CRSettingsFrost.myPrefs.DisableAutoMovement
                    && (Me.GroupInfo.IsInRaid || Me.IsInInstance || Me.GroupInfo.PartyMembers.Count() > 3))
                {
                    return false;
                }
                if ((GetAsyncKeyState(Keys.LButton) != 0
                    && GetAsyncKeyState(Keys.RButton) != 0) ||
                    GetAsyncKeyState(Keys.W) != 0 ||
                    GetAsyncKeyState(Keys.S) != 0 ||
                    GetAsyncKeyState(Keys.D) != 0 ||
                    GetAsyncKeyState(Keys.A) != 0)
                {
                    return false;
                }


                return CRSettingsFrost.myPrefs.AutoMovement;
            }
        }

        Composite CreateMovementBehavior()
        {
            return
                    new Action(ret =>
                    {
                        Navigator.MoveTo(StyxWoW.Me.CurrentTarget.Location);
                        return RunStatus.Failure;
                    }
                );
        }
        Composite CreateStopMovement()
        {
            return new Action(ret =>
            {
                Navigator.PlayerMover.MoveStop();
                return RunStatus.Failure;
            });
        }
        Composite CreateMoveBackBehavior()
        {
            return new Action(ret =>
            {
                WoWMovement.Move(WoWMovement.MovementDirection.Backwards);
                while (gotTarget && Me.CurrentTarget.IsAlive && Me.CurrentTarget.Distance < 10)
                {
                    break;
                }
                Navigator.PlayerMover.MoveStop();
                return RunStatus.Failure;
            });
        }
        float myRange
        {
            get
            {
                if (Me.CurrentTarget != null && IsWoWBoss(Me.CurrentTarget)) { return 5; }
                if ((Me.CurrentTarget != null && Me.CurrentTarget.IsPlayer)) { return 1.5f; }
                return 3.5f;
            }
        }
        public bool NeedGoBackwards
        {
            get
            {
                return Me.CurrentTarget != null && (Me.CurrentTarget.IsCasting && Me.CurrentTarget.CastingSpell.ToString() == "Blazing Cleave");
            }
        }
        #endregion

        #region facing
        Composite FaceMyTarget()
        {
            return
                new Action(ret =>
                {
                    Me.CurrentTarget.Face();
                    return RunStatus.Failure;
                });
        }
        #endregion

        #region pause
        public static bool PauseAoe = false;
        public static bool Paused = false;

        public static void HandleModifierStateChanged(object sender, LuaEventArgs args)
        {
            if (CRSettingsFrost.myPrefs.StopCRKey == CRSettingsFrost.Keypress.NONE
                && CRSettingsFrost.myPrefs.StopAoeKey == CRSettingsFrost.Keypress.NONE)
            {
                return;
            }
            if (Convert.ToInt32(args.Args[1]) == 1)
            {
                string pauseMyAoe = "AOE cancelled, press " + CRSettingsFrost.myPrefs.StopAoeKey.ToString() + " in WOW again to turn AOE back on";
                if (args.Args[0].ToString() == CRSettingsFrost.myPrefs.StopAoeKey.ToString())
                {
                    PauseAoe = !PauseAoe;
                    if (PauseAoe)
                    {
                        Logging.Write("Aoe cancelled, press {0} in WOW again to resume Aoe",
                                     CRSettingsFrost.myPrefs.StopAoeKey.ToString());
                        if (CRSettingsFrost.myPrefs.PrintRaidstyleMsg)
                            Lua.DoString(
                                "RaidNotice_AddMessage(RaidWarningFrame, \"" + pauseMyAoe + "\", ChatTypeInfo[\"RAID_WARNING\"]);");
                    }
                    else
                    {
                        Logging.Write("Aoe Resumed");
                        if (CRSettingsFrost.myPrefs.PrintRaidstyleMsg)
                            Lua.DoString(
                                "RaidNotice_AddMessage(RaidWarningFrame, \"Aoe Resumed !\", ChatTypeInfo[\"RAID_WARNING\"]);");
                    }
                }
            }
            if (Convert.ToInt32(args.Args[1]) == 1)
            {
                if (args.Args[0].ToString() == CRSettingsFrost.myPrefs.StopCRKey.ToString())
                {
                    string pauseCR = "CR paused, press " + CRSettingsFrost.myPrefs.StopCRKey.ToString() + " in WOW again to turn back on";
                    Paused = !Paused;
                    if (Paused)
                    {
                        Logging.Write("CR paused, press {0} in WOW again to turn back on",
                                     CRSettingsFrost.myPrefs.StopCRKey.ToString());
                        if (CRSettingsFrost.myPrefs.PrintRaidstyleMsg)
                            Lua.DoString(
                                "RaidNotice_AddMessage(RaidWarningFrame, \"" + pauseCR + "\", ChatTypeInfo[\"RAID_WARNING\"]);");
                    }
                    else
                    {
                        Logging.Write("CR running again ....");
                        if (CRSettingsFrost.myPrefs.PrintRaidstyleMsg)
                            Lua.DoString(
                                "RaidNotice_AddMessage(RaidWarningFrame, \"CR running again ....\", ChatTypeInfo[\"RAID_WARNING\"]);");
                    }
                }
            }
        }
        #endregion pause

        #region loot

        private double LootRange
        {
            get { return LootTargeting.LootRadius; }
        }
        private IOrderedEnumerable<WoWUnit> Lootables
        {
            get
            {
                var targetsList = ObjectManager.GetObjectsOfType<WoWUnit>(false, false).Where(
                        p => p.Lootable && p.Distance <= LootRange).OrderBy(l => l.Distance);
                return targetsList;
            }
        }
        private void GetLoot()
        {
            if (Me.IsCasting || Lootables.Count() == 0 || Me.IsMoving)
                return;
            if (LootFrame.Instance != null && LootFrame.Instance.IsVisible)
            {
                LootFrame.Instance.LootAll();
                if (Me.CurrentTarget != null && Me.CurrentTarget.IsDead)
                {
                    Me.ClearTarget();
                }
                return;
            }
            var lootTarget = Lootables.FirstOrDefault();
            if (lootTarget.Distance > lootTarget.InteractRange && !Me.GroupInfo.IsInParty && !Me.GroupInfo.IsInRaid && !Me.IsInInstance)
            {
                Logging.Write("Moving to loot {0}.", lootTarget.Name);
                Navigator.MoveTo(lootTarget.Location);
            }
            else
            {
                lootTarget.Interact();
                if (Me.CurrentTarget != null && Me.CurrentTarget.IsDead)
                {
                    Me.ClearTarget();
                }
                return;
            }
        }
        #endregion loot

        #region FindTarget
        WoWUnit FindTarget()
        {
            WoWUnit myTarget = ObjectManager.GetObjectsOfType<WoWUnit>(true, false).Where(u => ValidUnit(u)
                && u.DistanceSqr <= 8 * 8
                && !Blacklist.Contains(u, BlacklistFlags.All))
                .OrderBy(u => u.IsPlayer)
                .ThenBy(u => u.Distance)
                .FirstOrDefault();
            if (myTarget != null)
            {
                Logging.Write(Colors.PaleGreen, "Found new Target " + myTarget.Name);
                myTarget.Target();
                return myTarget;
            }
            return null;
        }
        #endregion

        #region crowdcontrol

        public bool IsCrowdControlledTarget(WoWUnit unit)
        {
            Dictionary<string, WoWAura>.ValueCollection auras = unit.Auras.Values;

            return unit.Fleeing
                || HasAuraWithEffect(unit,
                        WoWApplyAuraType.ModConfuse,
                        WoWApplyAuraType.ModCharm,
                        WoWApplyAuraType.ModFear,
                        WoWApplyAuraType.ModPossess);
        }

        public bool IsCrowdControlledPlayer(WoWUnit unit)
        {
            Dictionary<string, WoWAura>.ValueCollection auras = unit.Auras.Values;

            return unit.Rooted
                || unit.Fleeing
                || HasAuraWithEffect(unit,
                        WoWApplyAuraType.ModConfuse,
                        WoWApplyAuraType.ModCharm,
                        WoWApplyAuraType.ModFear,
                        WoWApplyAuraType.ModDecreaseSpeed,
                        WoWApplyAuraType.ModPacify,
                        WoWApplyAuraType.ModPacifySilence,
                        WoWApplyAuraType.ModPossess,
                        WoWApplyAuraType.ModRoot);
        }

        // this one optimized for single applytype lookup
        public bool HasAuraWithEffect(WoWUnit unit, WoWApplyAuraType applyType)
        {
            return unit.Auras.Values.Any(a => a.Spell != null && a.Spell.SpellEffects.Any(se => applyType == se.AuraType));
        }

        public static bool HasAuraWithEffect(WoWUnit unit, params WoWApplyAuraType[] applyType)
        {
            var hashes = new HashSet<WoWApplyAuraType>(applyType);
            return unit.Auras.Values.Any(a => a.Spell != null && a.Spell.SpellEffects.Any(se => hashes.Contains(se.AuraType)));
        }
        #endregion

        #region autoattack
        Composite AutoAttack()
        {
            return new Action(ret =>
            {
                Lua.DoString("StartAttack()");
                return RunStatus.Failure;
            });
        }
        #endregion

        #region paused pauseAoe
        Composite PauseCR()
        {
            return new Action(ret =>
            {
                return;
            });
        }
        #endregion

        #region Kind of target
        public bool IsWoWBoss(WoWUnit mytarget)
        {
            if (StyxWoW.Me.CurrentTarget != null)
            {
                if (StyxWoW.Me.CurrentTarget.CreatureRank == WoWUnitClassificationType.WorldBoss)
                {
                    return true;
                }
                else if (target.IsBoss(mytarget))
                {
                    return true;
                }
                else if (Me.CurrentTarget.MaxHealth >= (100 * 1000000)) { return true; }
                else if (StyxWoW.Me.CurrentTarget.CreatureRank == WoWUnitClassificationType.RareElite
                    && StyxWoW.Me.CurrentTarget.MaxHealth >= (StyxWoW.Me.MaxHealth * 4)
                    && (!StyxWoW.Me.GroupInfo.IsInParty
                    || StyxWoW.Me.GroupInfo.NumPartyMembers <= 3)
                    && !StyxWoW.Me.GroupInfo.IsInRaid
                    && !StyxWoW.Me.IsInInstance)
                {
                    return true;
                }
                else if (StyxWoW.Me.CurrentTarget.CreatureRank == WoWUnitClassificationType.Rare
                    && StyxWoW.Me.CurrentTarget.MaxHealth >= (StyxWoW.Me.MaxHealth * 4)
                    && (!StyxWoW.Me.GroupInfo.IsInParty
                    || StyxWoW.Me.GroupInfo.NumPartyMembers <= 3)
                    && !StyxWoW.Me.GroupInfo.IsInRaid
                    && !StyxWoW.Me.IsInInstance)
                {
                    return true;
                }
                else if (StyxWoW.Me.CurrentTarget.CreatureRank == WoWUnitClassificationType.Elite
                    && StyxWoW.Me.CurrentTarget.MaxHealth >= (StyxWoW.Me.MaxHealth * 4)
                    && (!StyxWoW.Me.GroupInfo.IsInParty
                    || StyxWoW.Me.GroupInfo.NumPartyMembers <= 3)
                    && !StyxWoW.Me.GroupInfo.IsInRaid
                    && !StyxWoW.Me.IsInInstance)
                {
                    return true;
                }
                else if (StyxWoW.Me.CurrentTarget.Name.Contains("Dummy")
                    && !StyxWoW.Me.IsInInstance)
                {
                    return true;
                }
                else if (StyxWoW.Me.CurrentTarget.IsPlayer
                    && !StyxWoW.Me.CurrentTarget.IsFriendly)
                {
                    return true;
                }
            }
            return false;
        }
        #endregion Kind of Target

        #region valid units
        public bool ValidUnit(WoWUnit p)
        {
            if (p == null || !p.IsValid)
                return false;

            // Ignore shit we can't select
            if (!p.CanSelect)
            {
                return false;
            }

            // Ignore shit we can't attack
            if (!p.Attackable)
            {
                return false;
            }

            // Duh
            if (p.IsDead)
            {
                return false;
            }

            // check for enemy players here as friendly only seems to work on npc's
            if (p.IsPlayer)
            {
                WoWPlayer pp = p.ToPlayer();
                if (pp.IsHorde == StyxWoW.Me.IsHorde)
                {
                    return false;
                }

                if (pp.Guid == StyxWoW.Me.CurrentTargetGuid && CanAttackCurrentTarget)
                {
                    return false;
                }

                return true;
            }

            // Ignore friendlies!
            if (p.IsFriendly)
            {
                return false;
            }
            // If it is a pet/minion/totem, lets find the root of ownership chain
            WoWPlayer pOwner = GetPlayerParent(p);

            // ignore if owner is player, alive, and not blacklisted then ignore (since killing owner kills it)
            // .. following .IsMe check to prevent treating quest mob summoned by us that we need to kill as invalid 
            if (pOwner != null && pOwner.IsAlive && !pOwner.IsMe)
            {
                if (!ValidUnit(pOwner))
                {
                    return false;
                }
                if (!Blacklist.Contains(pOwner, BlacklistFlags.Combat))
                {
                    return false;
                }
                if (!StyxWoW.Me.IsPvPFlagged)
                {
                    return false;
                }
            }

            // And ignore critters (except for those ferocious ones) /non-combat pets
            if (p.IsNonCombatPet)
            {
                return false;
            }

            // And ignore critters (except for those ferocious ones) /non-combat pets
            if (p.IsCritter && p.ThreatInfo.ThreatValue == 0 && !p.IsTargetingMyRaidMember)
            {
                return false;
            }
            /*
                        if (p.CreatedByUnitGuid != 0 || p.SummonedByUnitGuid != 0)
                            return false;
            */
            return true;
        }

        public WoWPlayer GetPlayerParent(WoWUnit unit)
        {
            // If it is a pet/minion/totem, lets find the root of ownership chain
            WoWUnit pOwner = unit;
            while (true)
            {
                if (pOwner.OwnedByUnit != null)
                    pOwner = pOwner.OwnedByRoot;
                else if (pOwner.CreatedByUnit != null)
                    pOwner = pOwner.CreatedByUnit;
                else if (pOwner.SummonedByUnit != null)
                    pOwner = pOwner.SummonedByUnit;
                else
                    break;
            }

            if (unit != pOwner && pOwner.IsPlayer)
                return pOwner as WoWPlayer;

            return null;
        }
        public bool CanAttackCurrentTarget
        {
            get
            {
                if (StyxWoW.Me.CurrentTarget == null)
                    return false;

                return Lua.GetReturnVal<bool>("return UnitCanAttack(\"player\",\"target\")", 0);
            }
        }
        #endregion

        #region eatfood
        Composite EatFood()
        {
            return new Decorator(ret => Me.HealthPercent <= CRSettingsFrost.myPrefs.FoodPercent && CanBuffEat && !Me.GroupInfo.IsInRaid && !Me.IsInInstance,
                new Action(ret =>
                {
                    Styx.CommonBot.Rest.Feed();
                    return RunStatus.Failure;
                }));
        }
        #endregion

        #region CanInterrupt
        
        WoWUnit InterruptableUnits()
        {
            WoWUnit myTarget = ObjectManager.GetObjectsOfType<WoWUnit>(true, false).Where(u => u != null
                && u.InLineOfSight
                && u.IsCasting
                && Me.CanInterruptCurrentSpellCast
                && !u.IsPet
                && !u.IsTotem
                && !u.IsFriendly
                && u.DistanceSqr <= 25 * 25)
                .OrderBy(u => u.IsPlayer)
                .ThenBy(u => u.Distance)
                .FirstOrDefault();
            if (myTarget != null)
            {
                return myTarget;
            }
            return null;
        }
        WoWUnit NonInterruptableUnits()
        {
            WoWUnit myTarget = ObjectManager.GetObjectsOfType<WoWUnit>(true, false).Where(u => u != null
                && u.InLineOfSight
                && u.IsCasting
                && !Me.CanInterruptCurrentSpellCast
                && !u.IsPet
                && !u.IsTotem
                && !u.IsFriendly
                && u.DistanceSqr <= 25 * 25)
                .OrderBy(u => u.IsPlayer)
                .ThenBy(u => u.Distance)
                .FirstOrDefault();
            if (myTarget != null)
            {
                return myTarget;
            }
            return null;
        }
        public Composite InterruptTarget()
        {
            return new Action(ret =>
            {
                var unit = InterruptableUnits();

                if (unit != null)
                {
                    if (SpellManager.HasSpell("Mind Freeze") && !spellOnCooldown("Mind Freeze") && SpellManager.CanCast("Mind Freeze") && unit.IsWithinMeleeRange)
                    {
                        SpellManager.Cast("Mind Freeze", unit);
                        Logging.Write(Colors.Yellow, "Interrupting " + unit.Name + " with Mind Freeze");
                        return RunStatus.Success;
                    }
                    if (SpellManager.HasSpell(ASPHYXIATE) && !spellOnCooldown(ASPHYXIATE) && SpellManager.CanCast(ASPHYXIATE))
                    {
                        SpellManager.Cast(ASPHYXIATE, unit);
                        Logging.Write(Colors.Yellow, "Interrupting " + unit.Name + " with Asphyxiate");
                        return RunStatus.Success;
                    }
                    if (SpellManager.HasSpell("Strangulate") && !spellOnCooldown("Strangulate") && SpellManager.CanCast("Strangulate"))
                    {
                        SpellManager.Cast("Strangulate", unit);
                        Logging.Write(Colors.Yellow, "Interrupting " + unit.Name + " with Strangulate");
                        return RunStatus.Success;
                    }
                    if (SpellManager.HasSpell("War Stomp") && !spellOnCooldown("War Stomp") && SpellManager.CanCast("War Stomp") && unit.IsWithinMeleeRange)
                    {
                        SpellManager.Cast("War Stomp", unit);
                        Logging.Write(Colors.Yellow, "Interrupting " + unit.Name + " with War Stomp");
                        return RunStatus.Success;
                    }
                }
                return RunStatus.Failure;
            }

                );
        }
        Composite StunningTarget()
        {
            return new Decorator(
                new Action(ret =>
                {

                    var unit = NonInterruptableUnits();

                    if (unit != null
                        && SpellManager.HasSpell("War Stomp")
                        && !spellOnCooldown("War Stomp")
                        && SpellManager.CanCast("War Stomp")
                        && unit.IsWithinMeleeRange)
                    {
                        SpellManager.Cast("War Stomp", unit);
                        Logging.Write(Colors.Red, "Stunning " + unit.Name + " with War Stomp");
                        return RunStatus.Success;
                    }
                    if (unit != null
                        && SpellManager.HasSpell(ASPHYXIATE)
                        && !spellOnCooldown(ASPHYXIATE)
                        && SpellManager.CanCast(ASPHYXIATE))
                    {
                        SpellManager.Cast(ASPHYXIATE, unit);
                        Logging.Write(Colors.Yellow, "Stunning " + unit.Name + " with Asphyxiate");
                        return RunStatus.Success;
                    }
                    if (unit != null
                        && SpellManager.HasSpell("Strangulate")
                        && !spellOnCooldown("Strangulate")
                        && SpellManager.CanCast("Strangulate"))
                    {
                        SpellManager.Cast("Strangulate", unit);
                        Logging.Write(Colors.Yellow, "Stunning " + unit.Name + " with Strangulate");
                        return RunStatus.Success;
                    }
                    return RunStatus.Failure;
                }));

        }
        #endregion

        #region Raise Ally

        public static List<WoWPlayer> Tanks
        {
            get
            {
                if (!StyxWoW.Me.GroupInfo.IsInParty)
                    return new List<WoWPlayer>(); ;

                return StyxWoW.Me.GroupInfo.RaidMembers.Where(p => p.HasRole(WoWPartyMember.GroupRole.Tank))
                    .Select(p => p.ToPlayer())
                    .Union(new[] { RaFHelper.Leader })
                    .Where(p => p != null && p.IsDead)
                    .Distinct()
                    .ToList();
            }
        }

        public static List<WoWPlayer> Healers
        {
            get
            {
                if (!StyxWoW.Me.GroupInfo.IsInParty)
                    return new List<WoWPlayer>(); ;

                return StyxWoW.Me.GroupInfo.RaidMembers.Where(p => p.HasRole(WoWPartyMember.GroupRole.Healer))
                    .Select(p => p.ToPlayer()).Where(p => p != null && p.IsDead).ToList();

            }
        }
        public static bool AnyTankNearby
        {
            get
            {
                return Tanks.Any(h => h.IsDead && h.Distance < 40);
            }
        }
        public static bool AnyHealerNearby
        {
            get
            {
                return Healers.Any(h => h.IsDead && h.Distance < 40);
            }
        }
        Composite ResTank()
        {
            return new Decorator(ret => CRSettingsFrost.myPrefs.AutoResTank && AnyTankNearby,
                new Action(ret =>
                {
                    var ResTankTarget = Tanks.FirstOrDefault();
                    if (ResTankTarget != null && ResTankTarget.InLineOfSight)
                    {
                        SpellManager.Cast("Raise Ally", ResTankTarget);
                        Logging.Write(Colors.Orange, "Ressing Tank" + ResTankTarget);
                        Lua.DoString("SendChatMessage(\"Resssing Tank\"" + ResTankTarget + ");");
                    }
                    return RunStatus.Failure;

                }));
        }
        Composite ResHealer()
        {
            return new Decorator(ret => CRSettingsFrost.myPrefs.AutoResHealer && AnyHealerNearby,
                new Action(ret =>
                {
                    var ResHealTarget = Healers.FirstOrDefault();
                    if (ResHealTarget != null && ResHealTarget.InLineOfSight)
                    {
                        SpellManager.Cast("Raise Ally", ResHealTarget);
                        Logging.Write(Colors.Orange, "Ressing Healer" + ResHealTarget);
                        string message = "Ressing " + ResHealTarget;
                        Lua.DoString("SendChatMessage(\"Resssing Healer \"" + ResHealTarget + ");");
                    }
                    return RunStatus.Failure;
                }));
        }
        #endregion

        #region useitems
        private static bool CanUseEquippedItem(WoWItem item)
        {
            // Check for engineering tinkers!
            string itemSpell = Lua.GetReturnVal<string>("return GetItemSpell(" + item.Entry + ")", 0);
            if (string.IsNullOrEmpty(itemSpell))
                return false;


            return item.Usable && item.Cooldown <= 0;
        }

        Composite Trinket1()
        {
            return
                new Decorator(ret => gotTarget && Me.Combat && CRSettingsFrost.myPrefs.AutoTrinket1 && (Me.CurrentTarget != null && Me.CurrentTarget.IsWithinMeleeRange),
                    new Action(ret =>
                    {
                        var firstTrinket = StyxWoW.Me.Inventory.Equipped.Trinket1;

                        if (CRSettingsFrost.myPrefs.trinket1hppercent > 0
                            && Me.ManaPercent <= CRSettingsFrost.myPrefs.trinket1hppercent
                            && firstTrinket != null
                            && CanUseEquippedItem(firstTrinket))
                        {
                            firstTrinket.Use();
                            return RunStatus.Success;
                        }
                        if (CRSettingsFrost.myPrefs.trinket1crowdcontrolled
                            && IsCrowdControlledPlayer(Me)
                            && firstTrinket != null
                            && CanUseEquippedItem(firstTrinket))
                        {
                            firstTrinket.Use();
                            return RunStatus.Success;
                        }
                        if (CRSettingsFrost.myPrefs.trinket1dpsboost
                            && IsWoWBoss(Me.CurrentTarget)
                            && firstTrinket != null
                            && CanUseEquippedItem(firstTrinket))
                        {
                            firstTrinket.Use();
                            return RunStatus.Success;
                        }
                        return RunStatus.Failure;
                    }));
        }
        Composite Trinket2()
        {
            return
                new Decorator(ret => gotTarget && Me.Combat && CRSettingsFrost.myPrefs.AutoTrinket2 && (Me.CurrentTarget != null && Me.CurrentTarget.IsWithinMeleeRange),
                    new Action(ret =>
                    {
                        var secondTrinket = StyxWoW.Me.Inventory.Equipped.Trinket2;

                        if (CRSettingsFrost.myPrefs.trinket2hppercent > 0
                            && Me.ManaPercent <= CRSettingsFrost.myPrefs.trinket2hppercent
                            && secondTrinket != null
                            && CanUseEquippedItem(secondTrinket))
                        {
                            secondTrinket.Use();
                            return RunStatus.Success;
                        }
                        if (CRSettingsFrost.myPrefs.trinket2crowdcontrolled
                            && IsCrowdControlledPlayer(Me)
                            && secondTrinket != null
                            && CanUseEquippedItem(secondTrinket))
                        {
                            secondTrinket.Use();
                            return RunStatus.Success;
                        }
                        if (CRSettingsFrost.myPrefs.trinket2dpsboost
                            && IsWoWBoss(Me.CurrentTarget)
                            && secondTrinket != null
                            && CanUseEquippedItem(secondTrinket))
                        {
                            secondTrinket.Use();
                            return RunStatus.Success;
                        }
                        return RunStatus.Failure;
                    }));
        }
        Composite Healthstone()
        {
            return new Decorator(ret => Me.Combat && Me.HealthPercent <= CRSettingsFrost.myPrefs.PercentHealthstone,
                new Action(ret =>
                {
                    var hstone = ObjectManager.GetObjectsOfType<WoWItem>().FirstOrDefault(item => item.Entry == 5512);
                    if (hstone != null && hstone.Usable)
                    {
                        hstone.Use();
                        Logging.Write("Using Healthstone");
                        return RunStatus.Success;
                    }
                    return RunStatus.Failure;
                }));
        }
        Composite AlchemyFlask()
        {
            return new Decorator(
                new Action(ret =>
                {
                    var alchflask = ObjectManager.GetObjectsOfType<WoWItem>().FirstOrDefault(item => item.Entry == 75525);
                    if (alchflask != null && alchflask.Usable && alchflask.Cooldown <= 0)
                    {
                        alchflask.Use();
                        return RunStatus.Success;
                    }
                    return RunStatus.Failure;
                }));
        }
        Composite CrystalOfInsanity()
        {
            return new Action(ret =>
            {
                var crystal = ObjectManager.GetObjectsOfType<WoWItem>().FirstOrDefault(item => item.Entry == 86569);
                if (crystal != null && crystal.Usable && crystal.Cooldown <= 0)
                {
                    crystal.Use();
                    return RunStatus.Success;
                }
                return RunStatus.Failure;
            });
        }
        #endregion

        #region death pact
        Composite CastDeathPact()
        {
            return new Decorator(ret => gotTarget && Me.HealthPercent <= CRSettingsFrost.myPrefs.DeathPactPercent && !spellOnCooldown(RAISE_DEAD) && !spellOnCooldown(DEATH_PACT),
                new Action(ret =>
                {
                    if (SpellManager.CanCast(RAISE_DEAD))
                    {
                        SpellManager.Cast(RAISE_DEAD);
                        SpellManager.Cast(DEATH_PACT);
                        Logging.Write(Colors.Orange, "Death Pact");
                        return RunStatus.Success;
                    }
                    return RunStatus.Failure;
                }));
        }
        #endregion


        #region Buff Checks

        public bool buffExists(int Buff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.GetAuraById(Buff);
                if (Results != null)
                    return true;
            }
            return false;
        }

        public double buffTimeLeft(int Buff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.GetAuraById(Buff);
                if (Results != null)
                {
                    if (Results.TimeLeft.TotalMilliseconds > 0)
                        return Results.TimeLeft.TotalMilliseconds;
                }
            }
            return 0;
        }

        public bool buffExists(string Buff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.GetAuraByName(Buff);
                if (Results != null)
                    return true;
            }
            return false;
        }

        public double buffTimeLeft(string Buff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.GetAuraByName(Buff);
                if (Results != null)
                {
                    if (Results.TimeLeft.TotalMilliseconds > 0)
                        return Results.TimeLeft.TotalMilliseconds;
                }
            }
            return 0;
        }



        public uint buffStackCount(int Buff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.GetAuraById(Buff);
                if (Results != null)
                    return Results.StackCount;
            }
            return 0;
        }
        public uint buffStackCount(string Buff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.GetAuraByName(Buff);
                if (Results != null)
                    return Results.StackCount;
            }
            return 0;
        }
        #endregion

        #region Cache Checks
        public IEnumerable<WoWAura> cachedAuras = new List<WoWAura>();
        public IEnumerable<WoWAura> cachedTargetAuras = new List<WoWAura>();
        public void getCachedAuras()
        {
            if (Me.CurrentTarget != null)
                cachedTargetAuras = Me.CurrentTarget.GetAllAuras();
            cachedAuras = Me.GetAllAuras();
        }
        #endregion

        #region Cooldown Checks
        private Dictionary<WoWSpell, long> Cooldowns = new Dictionary<WoWSpell, long>();
        public TimeSpan cooldownLeft(int Spell)
        {
            SpellFindResults Results;
            if (SpellManager.FindSpell(Spell, out Results))
            {
                WoWSpell Result = Results.Override ?? Results.Original;
                if (Cooldowns.TryGetValue(Result, out lastUsed))
                {
                    if (DateTime.Now.Ticks < lastUsed)
                        return Result.CooldownTimeLeft;
                    return TimeSpan.MaxValue;
                }
            }
            return TimeSpan.MaxValue;
        }
        public TimeSpan cooldownLeft(string Spell)
        {
            SpellFindResults Results;
            if (SpellManager.FindSpell(Spell, out Results))
            {
                WoWSpell Result = Results.Override ?? Results.Original;
                if (Cooldowns.TryGetValue(Result, out lastUsed))
                {
                    if (DateTime.Now.Ticks < lastUsed)
                        return Result.CooldownTimeLeft;
                    return TimeSpan.MaxValue;
                }
            }
            return TimeSpan.MaxValue;
        }
        long lastUsed;
        public int lastCast;
        public bool onCooldown(int Spell)
        {
            SpellFindResults Results;
            if (SpellManager.FindSpell(Spell, out Results))
            {
                WoWSpell Result = Results.Override ?? Results.Original;
                if (Cooldowns.TryGetValue(Result, out lastUsed))
                {
                    if (DateTime.Now.Ticks < lastUsed)
                        return Result.Cooldown;
                    return false;
                }
            }
            return false;
        }
        public bool onCooldown(string Spell)
        {
            SpellFindResults Results;
            if (SpellManager.FindSpell(Spell, out Results))
            {
                WoWSpell Result = Results.Override ?? Results.Original;
                if (Cooldowns.TryGetValue(Result, out lastUsed))
                {
                    if (DateTime.Now.Ticks < lastUsed)
                        return Result.Cooldown;
                    return false;
                }
            }
            return false;
        }
        public TimeSpan spellCooldownLeft(int Spell, bool useTracker = false)
        {
            if (useTracker)
                return cooldownLeft(Spell);
            SpellFindResults results;
            if (SpellManager.FindSpell(Spell, out results))
            {
                if (results.Override != null)
                    return results.Override.CooldownTimeLeft;
                return results.Override.CooldownTimeLeft;
            }
            return TimeSpan.MaxValue;
        }
        public TimeSpan spellCooldownLeft(string Spell, bool useTracker = false)
        {
            if (useTracker)
                return cooldownLeft(Spell);
            SpellFindResults results;
            if (SpellManager.FindSpell(Spell, out results))
            {
                if (results.Override != null)
                    return results.Override.CooldownTimeLeft;
                return results.Override.CooldownTimeLeft;
            }
            return TimeSpan.MaxValue;
        }
        public bool spellOnCooldown(int Spell, bool useTracker = false)
        {
            if (useTracker)
                return !onCooldown(Spell);
            SpellFindResults results;
            if (SpellManager.FindSpell(Spell, out results))
                return results.Override != null ? results.Override.Cooldown : results.Original.Cooldown;
            return false;
        }
        public bool spellOnCooldown(string Spell, bool useTracker = false)
        {
            if (useTracker)
                return !onCooldown(Spell);
            SpellFindResults results;
            if (SpellManager.FindSpell(Spell, out results))
                return results.Override != null ? results.Override.Cooldown : results.Original.Cooldown;
            return false;
        }
        #endregion

        #region Debuff Checks

        public bool debuffExists(int Debuff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                WoWAura aura = onTarget.GetAllAuras().FirstOrDefault(a => a.SpellId == Debuff && a.CreatorGuid == Me.Guid);
                if (aura != null)
                {
                    return true;
                }
            }
            return false;
        }

        public double debuffTimeLeft(int Debuff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                WoWAura aura = onTarget.GetAllAuras().FirstOrDefault(a =>
                    a.SpellId == Debuff
                    && a.CreatorGuid == Me.Guid);

                if (aura == null)
                {
                    return 0;
                }
                return aura.TimeLeft.TotalMilliseconds;
            }
            return 0;
        }

        public uint debuffStackCount(int Debuff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                WoWAura aura = onTarget.GetAllAuras().FirstOrDefault(a =>
                    a.SpellId == Debuff
                    && a.CreatorGuid == Me.Guid);

                if (aura == null)
                {
                    return 0;
                }
                return aura.StackCount;
            }
            return 0;
        }
        public bool debuffExists(string Debuff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                WoWAura aura = onTarget.GetAllAuras().FirstOrDefault(a => a.Name == Debuff && a.CreatorGuid == Me.Guid);
                if (aura != null)
                {
                    return true;
                }
            }
            return false;
        }

        public double debuffTimeLeft(string Debuff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                WoWAura aura = onTarget.GetAllAuras().FirstOrDefault(a =>
                    a.Name == Debuff
                    && a.CreatorGuid == Me.Guid);

                if (aura == null)
                {
                    return 0;
                }
                return aura.TimeLeft.TotalMilliseconds;
            }
            return 0;
        }

        public uint debuffStackCount(string Debuff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                WoWAura aura = onTarget.GetAllAuras().FirstOrDefault(a =>
                    a.Name == Debuff
                    && a.CreatorGuid == Me.Guid);

                if (aura == null)
                {
                    return 0;
                }
                return aura.StackCount;
            }
            return 0;
        }
        #endregion
    }
}
